<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <link rel="shortcut icon" href="/favicon.ico#" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
  <title>PagePlug</title>
  <style>
    :root {
      --loader-bar-color: #2CBBA6;
    }
    #loader {
      position: fixed;
      left: 0;
      top: 0;
      height: 3px;
      background: var(--loader-bar-color);
      transition: all ease-in 0.3s;
    }
  </style>
</head>

<body>
  <noscript>请在浏览器设置中开启 JS 支持😘</noscript>
  <div id="loader" style="width: 30vw;"></div>
  <!--
    To keep zIndex for tooltips higher than app comments, todo remove when migrating to Tooltip2
    Currently the className does not apply to the portal root, so we're unable to work with z-indexes based on that
  -->
  <div id="tooltip-root"></div>
  <div id="header-root"></div>
  <div id="root"></div>
  <script type="text/javascript">
    // Ref: https://github.com/Modernizr/Modernizr/blob/94592f279a410436530c7c06acc42a6e90c20150/feature-detects/storage/localstorage.js
    const getIsLocalStorageSupported = () => {
      try {
        window.localStorage.setItem("test", "testA");
        window.localStorage.removeItem("test");
        return true;
      } catch (e) {
        return false;
      }
    };
    const isLocalStorageSupported = getIsLocalStorageSupported();

    const handleLocalStorageNotSupportedError = () => {
      console.error("Localstorage storage is not supported on your device.");
    }

    const localStorageUtil = {
      getItem: (key) => {
        if (!isLocalStorageSupported) {
          handleLocalStorageNotSupportedError();
          return;
        }
        return window.localStorage.getItem(key);
      },
      removeItem: (key) => {
        if (!isLocalStorageSupported) {
          handleLocalStorageNotSupportedError();
          return
        }
        return window.localStorage.removeItem(key);
      },
      setItem: (key, value) => {
        if (!isLocalStorageSupported) {
          handleLocalStorageNotSupportedError();
          return;
        }
        return window.localStorage.setItem(key, value);
      }
    };

    // Note: The following handler is necessary for when we have a new deployment.

    // What happens?
    // The chunk hashes change, resulting in the server not able to find
    // the previous chunks which the client will keep requesting, until the "new" index.html
    // is loaded. This new index.html is loaded on page reload.

    // Current solution:
    // 1. Make sure it is indeed Appsmith's chunk which failed to fetch (regex match)
    // 2. Reload once, and don't reload again.
    // Pitfalls:
    // 1. First reload will not fetch the new index.html, if the server isn't yet ready to serve it.
    //    this can happen when the server is still deploying.

    // TODO(abhinav): A comprehensive solution is involve the user when repeated
    // reloads are necessary.
    // 1. Delay reloads in increasing durations
    // 2. Allow the user to pre-emptively reload or cancel reloads altogether.
    window.onerror = function(message, url) {
      const regex = /\/static\/js\/(\w.+).js$/;
      const chunkLoadErrorMessage = "Unexpected token '<'"
      if(regex.test(url) && url.indexOf(window.location.host) > -1 && message.includes(chunkLoadErrorMessage)) {
        console.error("chunk load failed!", url);
        // First check if we've set the flag to not reload on chunk load fail
        const donotReload = localStorageUtil.getItem("donotReloadOnChunkLoadFail");
          if(!donotReload){
            // If donotReload is set to false or undefined, we can set it to true and reload
            // This signifies that this is the first time this happened in this session.
            localStorageUtil.setItem("donotReloadOnChunkLoadFail", true);
            window.location.assign(window.location.href);
          }
      }
    };
    window.addEventListener("DOMContentLoaded", (event) => {
      document.getElementById("loader").style.width = "50vw";
    });
    window.addEventListener("load", (event) => {
      // This signifies that we've had a chunk load failure in this session
      // We clear the entry, as otherwise, we will have a repeated reload scenario.
      localStorageUtil.removeItem("donotReloadOnChunkLoadFail");

      document.getElementById("loader").style.width = "100vw";
      setTimeout(() => {
        document.getElementById("loader").style.opacity = 0;
      });
    });
    const registerPageServiceWorker = () => {
      if ("serviceWorker" in navigator) {
        window.addEventListener("load", function () {
          navigator.serviceWorker.register("/pageService.js").catch(error => {
            console.error("Service Worker Registration failed: " + error);
          });
        });
      }
    };
    registerPageServiceWorker();
  </script>
  <script type="text/javascript">
    // '' (empty strings), 'false' are falsy
    // could return either boolean or string based on value
    const parseConfig = (config) => {
      if (config.indexOf("__") === 0 || config.indexOf("$") === 0 || config.indexOf("%") === 0)
        return "";

      const result = config.trim();
      if (result.toLowerCase() === "false" || result === "") {
        return false;
      } else if (result.toLowerCase() === "true") {
        return true;
      }

      return result;
    }
    const LOG_LEVELS = ["debug", "error"];
    const CONFIG_LOG_LEVEL_INDEX = LOG_LEVELS.indexOf(parseConfig("__APPSMITH_CLIENT_LOG_LEVEL__"));

    const INTERCOM_APP_ID = parseConfig("%REACT_APP_INTERCOM_APP_ID%") || parseConfig("__APPSMITH_INTERCOM_APP_ID__");
    const CLOUD_HOSTING = parseConfig("__APPSMITH_CLOUD_HOSTING__");
    const DISABLE_TELEMETRY = parseConfig("__APPSMITH_DISABLE_TELEMETRY__");

    // Initialize the Intercom library
    if (INTERCOM_APP_ID.length) {
      (function () { var w = window; var ic = w.Intercom; if (typeof ic === "function") { ic('reattach_activator'); ic('update', w.intercomSettings); } else { var d = document; var i = function () { i.c(arguments); }; i.q = []; i.c = function (args) { i.q.push(args); }; w.Intercom = i; var l = function () { var s = d.createElement('script'); s.type = 'text/javascript'; s.async = true; s.src = 'https://widget.intercom.io/widget/' + INTERCOM_APP_ID; var x = d.getElementsByTagName('script')[0]; x.parentNode.insertBefore(s, x); }; if (document.readyState === 'complete') { l(); } else if (w.attachEvent) { w.attachEvent('onload', l); } else { w.addEventListener('load', l, false); } } })();
    }

    window.SENTRY_CONFIG = parseConfig("__APPSMITH_SENTRY_DSN__");
    window.APPSMITH_FEATURE_CONFIGS = {
      sentry: {
        dsn: parseConfig("__APPSMITH_SENTRY_DSN__"),
        release: parseConfig("__APPSMITH_SENTRY_RELEASE__"),
        environment: parseConfig("__APPSMITH_SENTRY_ENVIRONMENT__"),
      },
      smartLook: {
        id: parseConfig("__APPSMITH_SMART_LOOK_ID__"),
      },
      enableGoogleOAuth: parseConfig("__APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__"),
      enableGithubOAuth: parseConfig("__APPSMITH_OAUTH2_GITHUB_CLIENT_ID__"),
      enableRapidAPI: parseConfig("__APPSMITH_MARKETPLACE_ENABLED__"),
      segment: {
        apiKey: parseConfig("__APPSMITH_SEGMENT_KEY__"),
        ceKey: parseConfig("__APPSMITH_SEGMENT_CE_KEY__"),
      },
      fusioncharts: {
        licenseKey: parseConfig("__APPSMITH_FUSIONCHARTS_LICENSE_KEY__")
      },
      optimizely: parseConfig("__APPSMITH_OPTIMIZELY_KEY__"),
      enableMixpanel: parseConfig("__APPSMITH_SEGMENT_KEY__"),
      algolia: {
        apiId: parseConfig("__APPSMITH_ALGOLIA_API_ID__"),
        apiKey: parseConfig("__APPSMITH_ALGOLIA_API_KEY__"),
        indexName: parseConfig("__APPSMITH_ALGOLIA_SEARCH_INDEX_NAME__"),
      },
      logLevel: CONFIG_LOG_LEVEL_INDEX > -1 ? LOG_LEVELS[CONFIG_LOG_LEVEL_INDEX] : LOG_LEVELS[1],
      google: parseConfig("__APPSMITH_GOOGLE_MAPS_API_KEY__"),
      cloudHosting: CLOUD_HOSTING,
      enableTNCPP: parseConfig("__APPSMITH_TNC_PP__"),
      appVersion: {
        id: parseConfig("__APPSMITH_VERSION_ID__"),
        releaseDate: parseConfig("__APPSMITH_VERSION_RELEASE_DATE__")
      },
      intercomAppID: INTERCOM_APP_ID,
      mailEnabled: parseConfig("__APPSMITH_MAIL_ENABLED__"),
      disableTelemetry: DISABLE_TELEMETRY === "" || DISABLE_TELEMETRY,
      cloudServicesBaseUrl: parseConfig("__APPSMITH_CLOUD_SERVICES_BASE_URL__") || "https://cs.appsmith.com",
      googleRecaptchaSiteKey: parseConfig("__APPSMITH_RECAPTCHA_SITE_KEY__"),
    };
  </script>
</body>

</html>
